<template>
  <td
    class="table-cell body-cell"
    :class="{ 'is-editing': editing, 'is-required': field.required, 'is-error': error }"
    @click="onClick"
  >
    <CellEditor
      v-model="value"
      :editing.sync="editing"
      :placeholder="placeholder"
      :height="options.rowHeight"
      @tab="tabFocus"
    />

    <!-- 设置中 -->
    <template v-if="data.isSet">
      <!-- 扩展表格数据 -->
      <TableHandle v-if="!fieldIndex" :data="data" :item-index="itemIndex" />

      <!-- 头部隐藏时扩展字段数据 -->
      <TableHandle v-if="!itemIndex && options.headerHidden" :data="data" :field-index="fieldIndex" />
    </template>

    <!-- 填写中动态表格 -->
    <template v-else-if="data.isUse && options.dynamic">
      <!-- 扩展表格数据 -->
      <TableHandle v-if="!fieldIndex" :data="data" :item-index="itemIndex" />
    </template>
  </td>
</template>

<script lang="ts">
import { computed, defineComponent, inject, PropType, set } from 'vue'
import { Widget } from '@/models'
import { TableEditState, TableField, TableItem } from '@/types'
import CellEditor from './CellEditor.vue'
import TableHandle from './TableHandle.vue'

export default defineComponent({
  name: 'BodyCell',

  components: { CellEditor, TableHandle },

  props: {
    /** 控件数据 */
    data: {
      type: Widget,
      required: true
    },

    /** 字段 */
    field: {
      type: Object as PropType<TableField>,
      required: true
    },

    /** 数据 */
    item: {
      type: Object as PropType<TableItem>,
      required: true
    },

    /** 字段索引 */
    fieldIndex: {
      type: Number,
      required: true
    },

    /** 数据项索引 */
    itemIndex: {
      type: Number,
      required: true
    }
  },

  setup(props) {
    const state = inject('TableEditState') as TableEditState

    /** 表格选项 */
    const options = computed(() => props.data.tableOptions)

    /** 填写值 */
    const value = computed({
      set(val: string) {
        const { id } = props.field

        id && set(props.item, id, val)
      },

      get() {
        return (props.item[props.field.id || ''] as string) || ''
      }
    })

    /** 编辑状态 */
    const editing = computed({
      get() {
        const { fieldIndex, itemIndex } = props

        return fieldIndex === state.fieldIndex && itemIndex === state.itemIndex
      },

      set(val) {
        const { fieldIndex, itemIndex } = props

        if (val) {
          Object.assign(state, { fieldIndex, itemIndex })
        } else if (editing.value) {
          Object.assign(state, { fieldIndex: -1, itemIndex: -1 })
        }
      }
    })

    /** 数据项是否已填写 */
    function isItemFilled() {
      return !!props.data.tableValue[props.itemIndex]?.join('')
    }

    return {
      /** 表格选项 */
      options,

      /** 填写值 */
      value,

      /** 编辑状态 */
      editing,

      /** 占位 */
      placeholder: computed(() => {
        if (props.data.isDone) return ''

        const { placeholder, label } = props.field

        return placeholder || `请输入${label}`
      }),

      /**
       * 当前单元格是否填写错误
       * 1. 字段必填
       * 2. 单元格未填写
       * 3. 该行有填写
       * 4. 未聚焦该行
       */
      error: computed(
        () => props.field.required && !value.value && isItemFilled() && props.itemIndex !== state.itemIndex
      ),

      /** 点击单元格 */
      onClick(e: MouseEvent) {
        if (props.data.isUse) {
          e.stopPropagation()

          editing.value = true
        }
      },

      /** Tab 键聚焦编辑 */
      tabFocus(e: MouseEvent) {
        const isNext = !e.shiftKey

        let {
          fieldIndex,
          itemIndex,
          data: { tableFields, tableData }
        } = props
        const fieldIndexMax = tableFields.length - 1
        const itemIndexMax = tableData.length - 1

        if (isNext) {
          if (fieldIndex < fieldIndexMax) {
            fieldIndex++
          } else {
            fieldIndex = 0

            if (itemIndex < itemIndexMax) {
              itemIndex++
            } else {
              itemIndex = 0
            }
          }
        } else {
          if (fieldIndex > 0) {
            fieldIndex--
          } else {
            fieldIndex = fieldIndexMax

            if (itemIndex > 0) {
              itemIndex--
            } else {
              itemIndex = itemIndexMax
            }
          }
        }

        Object.assign(state, { fieldIndex, itemIndex })
      }
    }
  }
})
</script>

<style lang="scss">
.fa-widget-table-main .body-cell {
  &.is-required::after {
    position: absolute;
    top: 0;
    right: 0;
    border: 3px solid transparent;
    border-top-color: $color-danger;
    border-right-color: $color-danger;
    content: '';
  }
}
</style>
